package spring.cloud.tasks.executor.task.api;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import spring.cloud.tasks.common.curator.Curator;
import spring.cloud.tasks.common.nodepaths.TaskInstanceNodePaths;
import spring.cloud.tasks.common.nodepaths.TaskInstanceStageStatusChangeNodePaths;
import spring.cloud.tasks.common.status.TaskItemStatus;
import spring.cloud.tasks.executor.executor.Executor;
import spring.cloud.tasks.executor.executor.task.TaskExecutor;
import spring.cloud.tasks.executor.executor.task.execute_runtime_context.TaskItemExecuteRuntimeContext;
import spring.cloud.tasks.executor.executor.task.task_item_execute.TaskItemExecute;
import spring.cloud.tasks.executor.executor.task.task_item_execute.TaskItemExecuteRenewalInfoService;

import java.util.Date;
import java.util.concurrent.atomic.AtomicBoolean;

@Slf4j
@Setter
@Getter
public abstract class Task {
    /**
     * Scope("prototype")
     */
    public static final String scope_prototype = "prototype";
    private TaskItemExecute taskItemExecute;
    private volatile TaskItemExecuteRuntimeContext taskItemExecuteRuntimeContext;
    private String taskId;
    private String xid;
    private String taskInstanceId;
    private String taskStage;
    private String taskStage$type;
    private int taskStage$type$index;
    //
    private String taskProperties;
    private String taskInstanceProperties;
    private String taskItemIndexProperties;


    public void init(TaskItemExecute taskItemExecute,
                     TaskItemExecuteRuntimeContext taskItemExecuteRuntimeContext,
                     String taskId, String taskInstanceId, String taskStage, String taskStage$type, int taskStage$type$index,//
                     String xid, //
                     String taskProperties, String taskInstanceProperties, String taskItemIndexProperties) {//
        this.taskItemExecute = taskItemExecute;
        this.taskItemExecuteRuntimeContext = taskItemExecuteRuntimeContext;
        this.taskId = taskId;

        this.taskInstanceId = taskInstanceId;
        this.taskStage = taskStage;
        this.taskStage$type = taskStage$type;
        this.taskStage$type$index = taskStage$type$index;
        //
        this.xid = xid;
        //
        this.taskProperties = taskProperties;
        this.taskInstanceProperties = taskInstanceProperties;
        this.taskItemIndexProperties = taskItemIndexProperties;
    }


    /**
     * @throws InterruptedException 该异常代表程序应该主动结束后续代码的执行
     */
    public abstract void execute() throws InterruptedException;

    //
    public void statusCheckAndRenewal(String stage) throws InterruptedException {
        AtomicBoolean disRenewal = new AtomicBoolean(false);
        boolean statusCheck = statusCheck(stage, disRenewal);
        if (!statusCheck) {
            if (disRenewal.get()) {
                disrenewal();
            }
            throw new InterruptedException();
        } else {
            renewal();
        }
    }


    /**
     * 判断任务状态是否应该存活以及汇报业务线程自己还活着
     */
    public boolean statusCheck(String stage, AtomicBoolean disRenewal) throws InterruptedException {
        updateLastReportDate(stage);//即使外面的执行器，任务都已经被标记了，还是需要证明自己是活着的。
        return statusCheck(disRenewal);
    }

    public void updateLastReportDate(String stage) {
        this.taskItemExecuteRuntimeContext.lastReportDate = new Date();
        if (log.isDebugEnabled()) {
            log.debug("当前运行阶段为:" + stage);
        }
    }

    /**
     * 状态检查标准流程。一般情况任务分片线程都是正常的状态，校验流程都需要走完。如果校验流程中某一步提前异常了，在毫秒级内也能快速响应到。
     */
    public boolean statusCheck(AtomicBoolean disRenewal) {
        //Executor
        if (Executor.getNeedStopFlag()) {
            disRenewal.set(true);
            return false;
        }
        //任务分片.所在的执行器
        TaskExecutor taskExecutor = taskItemExecute.getTaskExecutor();
        if (taskExecutor.isNeedStop()) {
            disRenewal.set(true);
            return false;
        }
        boolean isAssigned = taskExecutor.getExecutor().getTaskMap().isAssigned(taskId, taskInstanceId, taskStage, taskStage$type, taskStage$type$index);
        if (!isAssigned) {
            disRenewal.set(true);
            return false;
        }
        if (taskItemExecute.needStop) {
            disRenewal.set(true);
            return false;
        }
        if (taskItemExecuteRuntimeContext.needStop) {
            disRenewal.set(true);
            return false;
        }
        //上下文信息最近+执行器信息远一点
        //任务分片.续期信息判断
        long nowDateTime = System.currentTimeMillis();
        if (nowDateTime > taskItemExecuteRuntimeContext.getMaxAllowRunningTime()) {
            taskItemExecuteRuntimeContext.needStop = true;
            taskItemExecuteRuntimeContext.needStopMessage = "已经超过最大的任务允许运行时间了";
            return false;
        }
        Long maxRenewalTime = taskItemExecuteRuntimeContext.getMaxRenewalTime();
        if (nowDateTime > maxRenewalTime) {
            taskItemExecuteRuntimeContext.needStop = true;
            taskItemExecuteRuntimeContext.needStopMessage = "已经超过最大的续期时间了";
            return false;
        }
        if (nowDateTime > taskItemExecuteRuntimeContext.getTimeoutDateTime().getTime()) {
            taskItemExecuteRuntimeContext.needStop = true;
            taskItemExecuteRuntimeContext.needStopMessage = "已经超过超时时间了";
            return false;
        }
        if (nowDateTime > taskItemExecuteRuntimeContext.getLockDateTime().getTime()) {
            taskItemExecuteRuntimeContext.needStop = true;
            taskItemExecuteRuntimeContext.needStopMessage = "已经超过锁结束时间了";
            return false;
        }
        return true;
    }

    /**
     * 必须是续期信息校验通过才进行续期。
     */
    private Boolean renewal() {
        //主动通知状态管理任务还存存活
        TaskExecutor taskExecutor = taskItemExecute.getTaskExecutor();
        TaskItemExecuteRenewalInfoService taskItemExecuteInfoService = taskExecutor.getTaskItemExecuteInfoService();
        TaskItemExecuteRuntimeContext.RenewalTimeInfo renewalTimeInfo = taskItemExecuteRuntimeContext.calculateNewRenewalInfo();
        Boolean renewal = taskItemExecuteInfoService.renewal(taskItemExecuteRuntimeContext, renewalTimeInfo);
        if (renewal == null) {
            return null;
        } else {
            if (renewal) {
                taskItemExecuteRuntimeContext.setMaxAllowRunningTime(renewalTimeInfo.maxAllowRunningTime);
                taskItemExecuteRuntimeContext.setMaxRenewalTime(renewalTimeInfo.maxRenewalTime);
                return true;
            } else {
                //taskItemExecuteRuntimeContext.needStop = true;
                //taskItemExecuteRuntimeContext.needStopMessage = "续期失败原因";
                return false;
            }
        }
    }

    private void disrenewal() {
        TaskExecutor taskExecutor = taskItemExecute.getTaskExecutor();
        TaskItemExecuteRenewalInfoService taskItemExecuteInfoService = taskExecutor.getTaskItemExecuteInfoService();
        taskItemExecuteInfoService.disrenewal(taskItemExecuteRuntimeContext);
    }

    //
    private String taskStageStatus;//只能有一个进行stage的状态汇报
    private String taskItemIndexStatus;

    /**
     * 需要提供taskItemIndexStatus、taskStageStatus的常量可以进行选择。
     *
     * @param taskStageStatus
     * @param taskItemIndexStatus
     * @throws InterruptedException
     */
    public void statusCheck(String taskItemIndexStatus, String taskItemIndexInfo, String taskStageStatus) throws InterruptedException {
        //单个stage+type状态汇报(优先)
        Curator curator = taskItemExecute.getTaskExecutor().getExecutor().getCurator();
        if (taskStageStatus != null) {
            //ZK更新stage状态,如果ZK上面已经是终止状态那么则不进行更新，本地打印警告信息。且把状态信息汇报到控制台。同时写入日志。
            String taskInstanceStatusNodePath = TaskInstanceNodePaths.getTaskInstanceSubNodePath(taskId, taskInstanceId, TaskInstanceNodePaths.TaskInstanceSubNode.status);
            //获取zk当前stage信息(stage+status)
            String status = curator.getData(taskInstanceStatusNodePath);
            if (status == null) {
                //
            } else {

            }
            //有实例阶段状态变更通知
            curator.delete(TaskInstanceStageStatusChangeNodePaths.getTaskInstanceStageStatusChangePath(taskId, taskInstanceId));
            curator.merge(TaskInstanceStageStatusChangeNodePaths.getTaskInstanceStageStatusChangePath(taskId, taskInstanceId), String.valueOf(System.currentTimeMillis()));
        }
        //单个分片执行汇报
        if (taskItemIndexStatus != null) {
            if (TaskItemStatus.status_handing.equals(taskItemIndexStatus)) {
                throw new IllegalStateException("不可以修改为运行状态");
            }
            //只能修改为终止状态
            boolean isTerminalState = TaskItemStatus.isTerminalState(taskItemIndexStatus);
            if (!isTerminalState) {
                throw new IllegalStateException("请传入终止状态值");
            }
            //ZK更新taskItemIndexStatus的执行状态
            String path = "/" + taskId + "/" + taskInstanceId + "/" + taskStage + "/" + taskStage$type + "/" + taskStage$type$index;
            String statusPath = path + "/" + "status";
            String markPath = path + "/" + "mark";
            String statusData = curator.getData(statusPath);
            if (!TaskItemStatus.status_handing.equals(statusData)) {
                curator.merge(statusPath, taskItemIndexStatus);//状态可以立即更新
            }
            String markData = curator.getData(markPath);
            if (markData == null) {
                markData = "";
            }
            markData += "状态:" + taskItemIndexStatus + ",处理信息:" + taskItemIndexInfo + ";";
            curator.merge(markPath, markData);
        }
    }

}
